"""
Case Type   : CM_Tools
Case Name   : 主节点数据盘满/xlog盘使用率超过85%
Create At   : 2025/5/22
Owner       : ningyali
Description :
    1.主节点执行业务
    2.查看集群状态
    3.主节点注入数据盘满故障
    4.查看集群状态
    5.查看主节点事务执行情况
Expect      :
    1.执行成功
    2.执行成功
    3.注入磁盘满成功
    4.执行成功
    5.主节点事务阻塞
History     :
"""

import os
import time
import unittest

from testcase.utils.ComInstall import CmInstall
from testcase.utils.ComInstall import CmUnInstall
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.ComThread import ComThread
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class CMServer(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.root_nodes = (Node('PrimaryRoot'), Node('Standby1Root'),
                           Node('Standby2Root'))
        self.user_nodes = (Node('PrimaryDbUser'), Node('Standby1DbUser'),
                           Node('Standby2DbUser'))
        self.common = Common()
        self.constant = Constant()
        self.t_name = 't_cm_tools_0018'

        text = '----prestep1:安装cm;expect:执行成功----'
        self.log.info(text)
        self.install_pkg_path = os.path.dirname(macro.DB_SCRIPT_PATH)
        self.cm = CmInstall(self.install_pkg_path, self.pri_sh.node.ssh_user)
        res = self.cm.update_xml_for_cm(*self.root_nodes)
        self.assertGreater(res.count('cmDir'), 1, f'执行失败: {text}')

        res = self.cm.cm_install(self.user_nodes[0])
        self.assertIn('Install CM tool success', res, f'执行失败: {text}')

    def test_trans(self):
        text = '----step1:主节点执行业务;expect:执行成功----'
        self.log.info(text)
        sql = f"create table {self.t_name}(id int,name varchar(100));" \
              f"insert into {self.t_name} values(generate_series(1,1000)," \
              f"'a_'||generate_series(1,1000));" \
              f"update {self.t_name} set name='cm' where id<200;" \
              f"delete from {self.t_name};" \
              f"select count(*) from {self.t_name};" \
              f"drop table {self.t_name} cascade;"
        pri_thread = ComThread(self.pri_sh.cycle_exec_sql, args=(sql, 1000))
        pri_thread.setDaemon(True)
        pri_thread.start()

        text = '----step2:查看集群状态;expect:执行成功----'
        self.log.info(text)
        q_cmd = f"source {macro.DB_ENV_PATH};" \
                f"cm_ctl query -v -C -i -d"
        q_res = self.common.get_sh_result(self.user_nodes[1], q_cmd)
        self.assertIn('cluster_state   : Normal', q_res, f'执行失败: {text}')

        text = '----step3:主节点注入数据盘满故障;expect:注入磁盘满成功----'
        self.log.info(text)
        avail_cmd = f"df -m {macro.DB_INSTANCE_PATH}|grep -iv Avail|" \
                    f"awk '{{{{print $4}}}}'"
        avail_res = self.common.get_sh_result(self.root_nodes[0], avail_cmd)
        self.assertGreater(int(avail_res.strip()), 0, f'执行失败: {text}')

        inject_cmd = f"fallocate -l {int(avail_res.strip()) * 0.86}M " \
                     f"{macro.DB_INSTANCE_PATH}/text.txt;"
        inject_res = self.common.get_sh_result(self.root_nodes[0], inject_cmd)
        self.assertEqual(len(inject_res.strip()), 0, f'执行失败: {text}')

        check_cmd = f'df -m {macro.DB_INSTANCE_PATH}|' \
                    f'grep -iv Avail|awk \'{{{{print $5}}}}\''
        check_res = self.common.get_sh_result(self.user_nodes[0], check_cmd)
        self.assertGreater(check_res.strip(), '85%', f'执行失败: {text}')

        text = '----step4:查看集群状态;expect:执行成功----'
        self.log.info(text)
        q_cmd = f"source {macro.DB_ENV_PATH};" \
                f"cm_ctl query -v -C -i -d"
        for i in range(10):
            time.sleep(10)
            q_res = self.common.get_sh_result(self.user_nodes[0], q_cmd)
            if 'Primary ReadOnly' in q_res:
                break
        self.assertIn('Primary ReadOnly', q_res, f'执行失败: {text}')

        text = '----step5:查看主节点事务执行情况;expect:主节点事务阻塞----'
        self.log.info(text)
        pri_thread.join(60)
        pri_res = pri_thread.get_result()
        self.log.info(pri_res)
        self.assertIsNone(pri_res, f'执行失败: {text}')

    def tearDown(self):
        text = '----poststep1:清理数据盘满故障;expect:执行成功----'
        self.log.info(text)
        inject_cmd = f"rm -rf {macro.DB_INSTANCE_PATH}/text.txt;" \
                     f"df -m {macro.DB_INSTANCE_PATH}|grep -iv Avail|" \
                     f"awk \'{{{{print $5}}}}\'"
        inject_res = self.common.get_sh_result(self.root_nodes[0], inject_cmd)

        text = '----poststep2:查看集群状态;expect:执行成功----'
        self.log.info(text)
        q_cmd = f"source {macro.DB_ENV_PATH};" \
                f"cm_ctl query -v -C -i -d"
        q_res = ''
        for i in range(10):
            time.sleep(10)
            q_res = self.common.get_sh_result(self.user_nodes[0], q_cmd)
            if 'Primary Normal' in q_res.splitlines()[-1].split('|')[0]:
                break
            elif 'Standby Normal' in q_res.splitlines()[-1].split('|')[0]:
                switch_cmd = f"source {macro.DB_ENV_PATH};cm_ctl switchover -a;"
                self.common.get_sh_result(self.user_nodes[0], switch_cmd)
                time.sleep(5)
                q_res = self.common.get_sh_result(self.user_nodes[0], q_cmd)

        text = '----poststep3:删除表;expect:执行成功----'
        self.log.info(text)
        sql = f"drop table if exists {self.t_name} cascade;"
        sql_res = self.pri_sh.execut_db_sql(sql)
        self.log.info(sql_res)

        text = '----poststep4:卸载cm;expect:执行成功----'
        self.log.info(text)
        self.un_cm = CmUnInstall(self.install_pkg_path,
                                 self.pri_sh.node.ssh_user)
        res = self.un_cm.cm_uninstall(
            self.user_nodes[0], '--deleteData --deleteBinary')

        self.assertLess(inject_res.strip(), '85%', f'执行失败: {text}')
        self.assertTrue(
            'Primary Normal' in q_res and q_res.count('Standby Normal') == 2,
            f'执行失败: {text}')
        self.assertIn(self.constant.DROP_TABLE_SUCCESS, sql_res,
                      f'执行失败: {text}')
        self.assertIn('Uninstall CM tool success', res, f'执行失败: {text}')
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
